package com.learn.criminalintent

import android.content.Context
import android.os.Bundle
import android.text.format.DateFormat
import android.util.Log
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import java.util.UUID

private const val TAG = "CrimeListFragment"

class CrimeListFragment : Fragment() {

    /**
     * 定义这样一个回调接口，把CrimeListFragment界面的点击事件代理给它的托管activity。
     */
    interface Callbacks {
        fun onCrimeSelected(crimeId: UUID)
    }

    private var callbacks: Callbacks? = null

    private lateinit var crimeRecyclerView: RecyclerView
    private var adapter: CrimeAdapter? = CrimeAdapter()

    private lateinit var emptyView: View
    private lateinit var addCrimeButton: View

    private val crimeListViewModel: CrimeListViewModel by lazy {
        ViewModelProviders.of(this).get(CrimeListViewModel::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG, "Called onCreate")
        setHasOptionsMenu(true)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        Log.d(TAG, "onCreateView $this")

        val view = inflater.inflate(R.layout.fragment_crime_list, container, false)

        crimeRecyclerView = view.findViewById(R.id.crime_recycler_view) as RecyclerView

        emptyView = view.findViewById(R.id.empty_view)
        addCrimeButton = view.findViewById(R.id.add_crime_button)

        addCrimeButton.setOnClickListener {
            val crime = Crime()
            crimeListViewModel.addCrime(crime)
            callbacks?.onCrimeSelected(crime.id)
        }

        crimeRecyclerView.layoutManager = LinearLayoutManager(context)
        crimeRecyclerView.adapter = adapter
        return view
    }

    /**
     * Fragment.onViewCreated(...)是在Fragment.onCreateView(...)函数之后调用的，调用到它表明fragment视图层级结构已创建完毕。
     */
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        Log.d(TAG, "Called onViewCreated")

        crimeListViewModel.crimeListLiveData.observe(
            viewLifecycleOwner,
            Observer { crimes ->
                crimes?.let {
                    Log.d(TAG, "Got crimes ${crimes.size}")
                    updateUI(crimes)
                }
            }
        )
    }

    /**
     * 当fragment附加到activity时，会调用Fragment.onAttach(Context)生命周期函数。
     */
    override fun onAttach(context: Context) {
        super.onAttach(context)
        Log.d(TAG, "Called onAttach")
        callbacks = context as Callbacks?
    }

    /**
     * 在Fragment.onDetach()这个没落生命周期函数里，我们把callbacks属性值设置为null。
     * 之所以这么做，是因为fragment随后就要和它的托管activity“说再见”了。
     */
    override fun onDetach() {
        super.onDetach()

        Log.d(TAG, "Called onDetach")
        callbacks = null
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        super.onCreateOptionsMenu(menu, inflater)

        // 使用 MenuInflater 将 XML 菜单资源解析为 Menu 对象
        // 并将其添加到 Fragment 的选项菜单中
        inflater.inflate(R.menu.fragment_crime_list, menu)
    }

    /**
     * 响应菜单项选择事件的回调函数
     */
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            R.id.new_crime -> {
                val crime = Crime()
                // 保存数据到数据库中
                crimeListViewModel.addCrime(crime)
                Log.d(TAG, "onOptionsItemSelected: ${crime.id}")

                //  MainActivity 实现了 Callbacks 接口，因此可以安全地调用 onCrimeSelected 方法。
                // 在调用 onCrimeSelected 的时候，传入id， MainActivity 会根据 id 查询 crime 并打开对应的 CrimeFragment（详情页）。
                callbacks?.onCrimeSelected(crime.id)
                true
            }

            else -> return super.onOptionsItemSelected(item)
        }
    }

    private fun updateUI(crimes: List<Crime>) {
        adapter?.submitList(crimes.toList())

        if (crimes.isEmpty()) {
            crimeRecyclerView.visibility = View.GONE
            emptyView.visibility = View.VISIBLE
        } else {
            crimeRecyclerView.visibility = View.VISIBLE
            emptyView.visibility = View.GONE
        }
    }

    /**
     * 设置为抽象类，更符合多态的思想。
     */
    private abstract inner class CrimeHolder(view: View) : RecyclerView.ViewHolder(view),
        View.OnClickListener {

        lateinit var crime: Crime

        private val titleTextView: TextView = itemView.findViewById(R.id.crime_title)
        private val dateTextView: TextView = itemView.findViewById(R.id.crime_date)
        private val solvedImageView: ImageView = itemView.findViewById(R.id.crime_solved)

        init {
            itemView.setOnClickListener(this)
        }

        open fun bind(crime: Crime) {
            this.crime = crime
            titleTextView.text = this.crime.title

            val date = DateFormat.format("yyyy-MM-dd HH:mm:ss EE", this.crime.date)
            dateTextView.text = date

            solvedImageView.visibility = if (this.crime.isSolved) {
                View.VISIBLE
            } else {
                View.GONE
            }
        }

        override fun onClick(v: View?) {
            Log.d(TAG, "CrimeHolder onClick Crime id:${crime.id}")
            callbacks?.onCrimeSelected(crime.id)
        }
    }

    private inner class NormalCrimeHolder(view: View) : CrimeHolder(view) {}

    private inner class SeriousCrimeHolder(view: View) : CrimeHolder(view) {}

    private inner class CrimeAdapter() :
        ListAdapter<Crime, CrimeHolder>(CrimeDiffCallBack) {

        /**
         * onCreateViewHolder 负责创建要显示的视图，将其封装到一个ViewHolder里并返回结果。
         */
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CrimeHolder {
            val view = layoutInflater.inflate(viewType, parent, false)
            if (viewType == R.layout.list_item_serious_crime) {
                return SeriousCrimeHolder(view)
            } else {
                return NormalCrimeHolder(view)
            }
        }

        /**
         * 负责将数据集里指定位置的crime数据发送给指定ViewHolder。
         */
        override fun onBindViewHolder(holder: CrimeHolder, position: Int) {
            holder.bind(getItem(position))
        }

        override fun getItemViewType(position: Int): Int {
            if (getItem(position).isSolved) {
                return R.layout.list_item_serious_crime
            } else {
                return R.layout.list_item_crime
            }
        }
    }

    private object CrimeDiffCallBack : DiffUtil.ItemCallback<Crime>() {
        override fun areItemsTheSame(oldItem: Crime, newItem: Crime): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: Crime, newItem: Crime): Boolean {
            // 比较所有影响UI展示的字段
            return oldItem.title == newItem.title &&
                    oldItem.date == newItem.date &&
                    oldItem.isSolved == newItem.isSolved
        }

    }

    companion object {
        fun newInstance(): CrimeListFragment {
            return CrimeListFragment()
        }
    }
}